<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
<meta name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">

    <meta name="author" content="Mouweng">





<title>Redis集群与持久化 | Mouweng&#39;s Blog</title>



    <link rel="icon" href="/favicon.ico">




    <!-- stylesheets list from _config.yml -->
    
    <link rel="stylesheet" href="/css/style.css">
    



    <!-- scripts list from _config.yml -->
    
    <script src="/js/script.js"></script>
    
    <script src="/js/tocbot.min.js"></script>
    



    
    
        
    


<meta name="generator" content="Hexo 5.1.1"><link rel="alternate" href="/atom.xml" title="Mouweng's Blog" type="application/atom+xml">
</head>
<body>
    <div class="wrapper">
        <header>
    <nav class="navbar">
        <div class="container">
            <div class="navbar-header header-logo"><a href="/">Mouweng</a></div>
            <div class="menu navbar-right">
                
                    <a class="menu-item" href="/archives">Posts</a>
                
                    <a class="menu-item" href="/category">Categories</a>
                
                    <a class="menu-item" href="/tag">Tags</a>
                
                    <a class="menu-item" href="/about">About</a>
                
                <input id="switch_default" type="checkbox" class="switch_default">
                <label for="switch_default" class="toggleBtn"></label>
            </div>
        </div>
    </nav>

    
    <nav class="navbar-mobile" id="nav-mobile">
        <div class="container">
            <div class="navbar-header">
                <div>
                    <a href="/">Mouweng</a><a id="mobile-toggle-theme">·&nbsp;Light</a>
                </div>
                <div class="menu-toggle" onclick="mobileBtn()">&#9776; Menu</div>
            </div>
            <div class="menu" id="mobile-menu">
                
                    <a class="menu-item" href="/archives">Posts</a>
                
                    <a class="menu-item" href="/category">Categories</a>
                
                    <a class="menu-item" href="/tag">Tags</a>
                
                    <a class="menu-item" href="/about">About</a>
                
            </div>
        </div>
    </nav>

</header>
<script>
    var mobileBtn = function f() {
        var toggleMenu = document.getElementsByClassName("menu-toggle")[0];
        var mobileMenu = document.getElementById("mobile-menu");
        if(toggleMenu.classList.contains("active")){
           toggleMenu.classList.remove("active")
            mobileMenu.classList.remove("active")
        }else{
            toggleMenu.classList.add("active")
            mobileMenu.classList.add("active")
        }
    }
</script>
        <div class="main">
            <div class="container">
    
    
        <div class="post-toc">
    <div class="tocbot-list">
    </div>
    <div class="tocbot-list-menu">
        <a class="tocbot-toc-expand" onclick="expand_toc()">Expand all</a>
        <a onclick="go_top()">Back to top</a>
        <a onclick="go_bottom()">Go to bottom</a>
    </div>
</div>

<script>
    document.ready(
        function () {
            tocbot.init({
                tocSelector: '.tocbot-list',
                contentSelector: '.post-content',
                headingSelector: 'h1, h2, h3, h4, h5',
                collapseDepth: 1,
                orderedList: false,
                scrollSmooth: true,
            })
        }
    )

    function expand_toc() {
        var b = document.querySelector(".tocbot-toc-expand");
        tocbot.init({
            tocSelector: '.tocbot-list',
            contentSelector: '.post-content',
            headingSelector: 'h1, h2, h3, h4, h5',
            collapseDepth: 6,
            orderedList: false,
            scrollSmooth: true,
        });
        b.setAttribute("onclick", "collapse_toc()");
        b.innerHTML = "Collapse all"
    }

    function collapse_toc() {
        var b = document.querySelector(".tocbot-toc-expand");
        tocbot.init({
            tocSelector: '.tocbot-list',
            contentSelector: '.post-content',
            headingSelector: 'h1, h2, h3, h4, h5',
            collapseDepth: 1,
            orderedList: false,
            scrollSmooth: true,
        });
        b.setAttribute("onclick", "expand_toc()");
        b.innerHTML = "Expand all"
    }

    function go_top() {
        window.scrollTo(0, 0);
    }

    function go_bottom() {
        window.scrollTo(0, document.body.scrollHeight);
    }

</script>
    

    
    <article class="post-wrap">
        <header class="post-header">
            <h1 class="post-title">Redis集群与持久化</h1>
            
                <div class="post-meta">
                    
                        Author: <a itemprop="author" rel="author" href="/">Mouweng</a>
                    

                    
                        <span class="post-time">
                        Date: <a href="#">August 27, 2020&nbsp;&nbsp;23:41:12</a>
                        </span>
                    
                    
                        <span class="post-category">
                    Category:
                            
                                <a href="/categories/redis/">redis</a>
                            
                        </span>
                    
                </div>
            
        </header>

        <div class="post-content">
            <h2 id="redis持久化"><a href="#redis持久化" class="headerlink" title="redis持久化"></a>redis持久化</h2><p>Redis支持两种方式的持久化，一种是RDB方式，另一种是AOF方式。前者会根据指定的规则定时将内存中的数据存储到硬盘上，后者在每次执行命令后将命令本身记录下来。</p>
<h3 id="RDB方式"><a href="#RDB方式" class="headerlink" title="RDB方式"></a>RDB方式</h3><hr>
<p>将某个时间点的所有数据都存放到硬盘上，如果系统发生故障，将会丢失最后一次创建快照之后的数据。如果数据量很大，保存快照的时间会很长。</p>
<p><strong>Redis会在以下几种情况下对数据进行快照</strong></p>
<ul>
<li>根据配置规则进行自动快照</li>
<li>用户执行SAVE或BGSAVE命令</li>
<li>执行FLUSHALL命令</li>
<li>执行复制时</li>
</ul>
<p><strong>快照原理</strong></p>
<ol>
<li>redis使用fork函数复制当前进程的副本</li>
<li>原进程继续处理客户端请求，副本进程开始将内存中的数据写入硬盘中的临时文件</li>
<li>写完所有数据之后用临时文件替换旧的RDB文件（<strong>RDB文件存储的是fork执行那一刻的内存数据</strong>，如果中间数据修改，操作系统会将该数据复制一份以保证副本进程不受影响）</li>
</ol>
<h3 id="AOF方式"><a href="#AOF方式" class="headerlink" title="AOF方式"></a>AOF方式</h3><hr>
<blockquote>
<p>将写命令添加到硬盘中的 AOF 文件（Append Only File）的末尾。</p>
</blockquote>
<p>使用 AOF 持久化需要设置同步选项，从而确保写命令同步到磁盘文件上的时机。这是因为对文件进行写入并不会马上将内容同步到磁盘上，而是先存储到缓冲区，然后由操作系统决定什么时候同步到磁盘。有以下同步选项：</p>
<table>
<thead>
<tr>
<th>选项</th>
<th align="left">同步频率</th>
</tr>
</thead>
<tbody><tr>
<td>always</td>
<td align="left">每个写命令都同步</td>
</tr>
<tr>
<td>everysec</td>
<td align="left">每秒同步一次</td>
</tr>
<tr>
<td>no</td>
<td align="left">让操作系统来决定何时同步</td>
</tr>
</tbody></table>
<ul>
<li>always 选项会严重减低服务器的性能；</li>
<li>everysec 选项比较合适，可以保证系统崩溃时只会丢失一秒左右的数据，并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响；</li>
<li>no 选项并不能给服务器性能带来多大的提升，而且也会增加系统崩溃时数据丢失的数量。</li>
</ul>
<p>随着服务器写请求的增多，AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性，能够去除 AOF 文件中的冗余写命令。</p>
<h2 id="redis复制"><a href="#redis复制" class="headerlink" title="redis复制"></a>redis复制</h2><hr>
<blockquote>
<p>通过使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。一个主服务器可以有多个从服务器，而一个从服务器只能有一个主服务器。</p>
</blockquote>
<p><strong>原理</strong></p>
<ol>
<li>从服务器启动，向主服务器法发送SYNC命令，主服务器保存快照，并将保存快照期间接受到的命令缓存起来，然后把快照文件和缓存时的命令一并发送给从服务器</li>
<li>从服务器丢弃所有旧数据，载入主服务器发来的快照文件，再执行缓存时的命令</li>
<li>主服务器每一次执行写命令，就向从服务器发送相同的写命令（异步，故是乐观复制）</li>
</ol>
<p><strong>主从链</strong></p>
<p>主从链是通过创建中间层来分担主服务器的复制工作。</p>
<p>为了降低主服务器的压力，可以让主服务器只负责写操作，而从服务器实现读操作。</p>
<p><img src="https://tva1.sinaimg.cn/large/006tNbRwgy1g9hje68jwhj30l40ay0t5.jpg"></p>
<p><strong>无硬盘复制</strong></p>
<p>开启该选项时，Redis在与从服务器进行复制初始化时不会将快照内容存储到硬盘上，而是直接通过网络发送给从数据库，避免了硬盘的性能瓶颈。</p>
<p><strong>增量复制</strong></p>
<p>主数据库只需将断线重连期间执行的命令传送给从数据库即可，通过积压队列和偏移量实现。</p>
<h2 id="哨兵（Sentinel）"><a href="#哨兵（Sentinel）" class="headerlink" title="哨兵（Sentinel）"></a>哨兵（Sentinel）</h2><hr>
<p>Sentinel（哨兵）可以监听集群中的服务器，并在主服务器进入下线状态时，自动从从服务器中选举出新的主服务器。</p>
<p><strong>原理</strong></p>
<ol>
<li>每10s哨兵会向主数据库和从数据库发送info命令。（用来更新主从数据库的角色信息，只连接主数据库也能找到所有的从数据库）</li>
<li>每2s哨兵会向主数据库和从数据库的碰到发送自己的信息。（检测有无新的哨兵出现）</li>
<li>每1s哨兵向主数据库、从数据库和其他哨兵结点发送PING命令</li>
</ol>
<p>判定服务器下线时，达到指定数量（自己设定），哨兵会认为期客观下线</p>
<p>选举哨兵结点恢复故障时采用Raft算法（一半的哨兵投票通过）</p>
<h2 id="分片"><a href="#分片" class="headerlink" title="分片"></a>分片</h2><hr>
<p>分片是将数据划分为多个部分的方法，可以将数据存储到多台机器里面，这种方法在解决某些问题时可以获得线性级别的性能提升。</p>
<p>假设有 4 个 Redis 实例 R0，R1，R2，R3，还有很多表示用户的键 user:1，user:2，… ，有不同的方式来选择一个指定的键存储在哪个实例中。</p>
<ul>
<li>最简单的方式是范围分片，例如用户 id 从 0<del>1000 的存储到实例 R0 中，用户 id 从 1001</del>2000 的存储到实例 R1 中，等等。但是这样需要维护一张映射范围表，维护操作代价很高。</li>
<li>还有一种方式是哈希分片，使用 CRC32 哈希函数将键转换为一个数字，再对实例数量求模就能知道应该存储的实例。</li>
</ul>
<p>根据执行分片的位置，可以分为三种分片方式：</p>
<ul>
<li>客户端分片：客户端使用一致性哈希等算法决定键应当分布到哪个节点。</li>
<li>代理分片：将客户端请求发送到代理上，由代理转发请求到正确的节点上。</li>
<li>服务器分片：Redis Cluster。</li>
</ul>

        </div>

        
            <section class="post-copyright">
                
                
                
                

            </section>
        
        <section class="post-tags">
            <div>
                <span>Tag(s):</span>
                <span class="tag">
                    
                    
                        <a href="/tags/redis/"># redis</a>
                    
                        <a href="/tags/%E9%9B%86%E7%BE%A4/"># 集群</a>
                    
                        <a href="/tags/%E6%8C%81%E4%B9%85%E5%8C%96/"># 持久化</a>
                    
                        
                </span>
            </div>
            <div>
                <a href="javascript:window.history.back();">back</a>
                <span>· </span>
                <a href="/">home</a>
            </div>
        </section>
        <section class="post-nav">
            
                <a class="prev" rel="prev" href="/2020/08/27/Java%E5%BC%82%E5%B8%B8/">Java异常</a>
            
            
            <a class="next" rel="next" href="/2020/08/27/%E5%8C%85%E8%A3%85%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%88%AB/">包装类型和基本类型的区别</a>
            
        </section>


    </article>
</div>

        </div>
        <footer id="footer" class="footer">
    <div class="copyright">
        <span>© Mouweng | Powered by <a href="https://hexo.io" target="_blank">Hexo</a> & <a href="https://github.com/Siricee/hexo-theme-Chic" target="_blank">Chic</a></span>
    </div>
</footer>

    </div>
</body>
</html>
